use std::collections::HashMap;

use cgmath::{vec3, Matrix4, One, Quaternion, SquareMatrix, Vector3, Zero};

use crate::engine::ISystem;

pub struct Component {
    position: Vector3<f32>,
    rotation: Quaternion<f32>,
    scale: Vector3<f32>,

    matrix_cache: Matrix4<f32>,
    dirty: bool,
}

impl Component {
    pub fn new() -> Self {
        Self {
            position: Vector3::zero(),
            rotation: Quaternion::one(),
            scale: vec3(1.0, 1.0, 1.0),

            matrix_cache: Matrix4::identity(),
            dirty: false,
        }
    }

    pub fn update(&mut self) {
        if self.dirty {
            self.matrix_cache = Matrix4::from_translation(self.position)
                * Matrix4::from(self.rotation)
                * Matrix4::from_nonuniform_scale(self.scale.x, self.scale.y, self.scale.z);
            self.dirty = false
        }
    }

    pub fn position(&self) -> Vector3<f32> {
        self.position
    }

    pub fn position_mut(&mut self) -> &mut Vector3<f32> {
        self.dirty = true;
        &mut self.position
    }

    pub fn rotation(&self) -> Quaternion<f32> {
        self.rotation
    }

    pub fn rotation_mut(&mut self) -> &mut Quaternion<f32> {
        self.dirty = true;
        &mut self.rotation
    }

    pub fn scale(&self) -> Vector3<f32> {
        self.scale
    }

    pub fn scale_mut(&mut self) -> &mut Vector3<f32> {
        self.dirty = true;
        &mut self.scale
    }

    pub fn combined_matrix(&self) -> &Matrix4<f32> {
        &self.matrix_cache
    }
}

pub struct System {
    components: HashMap<usize, Component>,
}

impl System {
    pub fn new() -> Self {
        Self {
            components: HashMap::new(),
        }
    }

    pub fn update(&mut self) {
        for component in self.components.values_mut() {
            component.update()
        } 
    }
}

impl ISystem<Component> for System {
    fn components(&self) -> &HashMap<usize, Component> {
        &self.components
    }

    fn components_mut(&mut self) -> &mut HashMap<usize, Component> {
        &mut self.components
    }
}
